use std::cmp::Ordering;
use std::hash::Hash;

use halo_model::ExtensionOperator;
/*
public_struct!(
    pub struct UserBase {
        username: String,
        email: String,
        full_name: Option<String>,
    }
);
UserBase!(
    pub struct UserIn {
        pub password: String,
    }
);

public_struct!(
    // pub is required here before struct
    pub struct MessageBase {
        pub text: String, // pub text: String // , is not required for the struct definition.
    }
);

MessageBase!(
    #[derive(Debug, Clone, PartialEq)]
    pub struct Message {
        pub read: bool,
        // read: bool, // pub is optional.
    }
);

impl Message {
    fn update_text(&mut self, new_message: String) {
        self.text = new_message
    }
    fn read(&mut self) {
        if self.read == false {
            self.read = true;
        }
    }
}*/



pub enum Comparators {
    CompareCreationTimestamp(bool),

    CompareName(bool),

    DefaultComparator,
}

impl Comparators {
    pub fn comparing<T>(comparators: Comparators) -> Box<dyn Fn(&T, &T) -> Ordering>
    where
        T: ExtensionOperator,
    {
        match comparators {
            Comparators::CompareCreationTimestamp(asc) => {
                return if asc {
                    Box::new(|a: &T, b: &T| do_comparing_creation_timestamp(a, b))
                } else {
                    Box::new(|a: &T, b: &T| do_comparing_creation_timestamp(a, b).reverse())
                };
            }
            Comparators::CompareName(asc) => {
                return if asc {
                    Box::new(|a: &T, b: &T| do_comparing_name(a, b))
                } else {
                    Box::new(|a: &T, b: &T| do_comparing_name(a, b).reverse())
                };
            }
            Comparators::DefaultComparator => Box::new(|a: &T, b: &T| {
                do_comparing_creation_timestamp(a, b).then_with(|| do_comparing_name(a, b))
            }),
        }
    }
}

fn do_comparing_creation_timestamp<T>(a: &T, b: &T) -> Ordering
where
    T: ExtensionOperator,
{
    let creation_timestamp1 = a.get_metadata().get_creation_timestamp().clone();
    let creation_timestamp2 = b.get_metadata().get_creation_timestamp().clone();
    return if creation_timestamp1.is_some() && creation_timestamp2.is_some() {
        let time1 = creation_timestamp1.unwrap();
        let time2 = creation_timestamp2.unwrap();
        time1.cmp(&time2)
    } else if creation_timestamp1.is_some() && creation_timestamp2.is_none() {
        Ordering::Greater
    } else if creation_timestamp1.is_none() && creation_timestamp2.is_some() {
        Ordering::Less
    } else {
        Ordering::Equal
    };
}

fn do_comparing_name<T>(a: &T, b: &T) -> Ordering
where
    T: ExtensionOperator,
{
    let name1 = a.get_metadata().get_name().clone();
    let name2 = b.get_metadata().get_name().clone();
    return name1.cmp(&name2);
}
